/**    
 * 文件名：ColorDetector.java    
 *    
 * 版本信息：    
 * 日期：2014年3月7日    
 * xyj 足下 xyj 2014     
 * 版权所有    
 *    
 */
package opencvtest.chapter03;

import static java.lang.Math.abs;
import static java.lang.Math.max;
import static opencvtest.OpenCVImageJUtils.toBufferedImage;
import static opencvtest.OpenCVImageJUtils.toColorProcessor;
import ij.process.ByteProcessor;
import ij.process.ColorProcessor;

import java.awt.Color;

import com.googlecode.javacv.cpp.opencv_core.IplImage;

/**
 * Example of using a strategy pattern in algorithm design.
 * 
 * The pattern encapsulates an algorithm into a separate class. To run this
 * example use [[opencv2_cookbook.chapter03.Ex1ColorDetector]].
 * 
 * The algorithm converts the input image to a binary by checking is pixel color
 * is within a given distance from a desired color. Pixels with color close to
 * the desired color are white, other black.
 * 
 * This Scala code functionally is equivalent to C++ code in chapter 3 section
 * "Using the Strategy pattern in algorithm design". The original example in the
 * book is using "C++ API". To make operations on image pixels easier and more
 * efficient OpenCV color image is converted to ImageJ representation during
 * processing.
 * 
 * Unlike the in the C++ example, this class does not pre-allocates and hold
 * space for process image, it is create only when needed.
 */
public class ColorDetector {

    private final int colorDistanceThreshold;

    private final Color targetColor;

    public ColorDetector(int minDist, Color colorRGB) {
        this.colorDistanceThreshold = max(0, minDist);
        this.targetColor = colorRGB;
    }

    public IplImage process(IplImage iplImage) {

        // Convert to ImageJ's ColorProcessor for easier pixel access
        ColorProcessor src = toColorProcessor(iplImage);
        // Create output image
        ByteProcessor dest = new ByteProcessor(src.getWidth(), src.getHeight());

        // Iterate through pixels and check if their distance from the target
        // color is
        // withing the distance threshold, if it is set `dest` to 255.
        for (int y = 0; y < src.getHeight(); y++) {
            for (int x = 0; x < src.getWidth(); x++) {
                if (distance(src.getColor(x, y)) < colorDistanceThreshold) {
                    dest.set(x, y, 255);
                }
            }
        }

        // Convert back to OpenCV's IplImage
        return IplImage.createFrom(toBufferedImage(dest));
    }

    private double distance(Color color) {
        return abs(targetColor.getRed() - color.getRed()) + abs(targetColor.getGreen() - color.getGreen())
                + abs(targetColor.getBlue() - color.getBlue());
    }

    public static void main(String[] args) {

        Color color1 = new Color(130, 190, 230);
        Color color2 = new Color(255, 255, 255);

        double dist = abs(color1.getRed() - color2.getRed()) + abs(color1.getGreen() - color2.getGreen())
                + abs(color1.getBlue() + color2.getRed());
        System.out.println(dist);

    }
}
